#include "amever.h"
#include "lua_w.h"

int luaw_init(void) {
 s.L = lua_open();
 luaopen_base(s.L);
 luaopen_io(s.L);
 luaopen_table(s.L);
 luaopen_string(s.L);
 luaopen_math(s.L);
 luaopen_debug(s.L);
 luaw_registerFunctions (s.L);
 amelog("Lua wrapper inited.\n");
 return 0;
}

void luaw_shut(void) {
	amelog("Closing lua wrapper.\n");
	if (s.L) {
		lua_close(s.L);
	}
}

/* LUA Wrapping funx */
struct luaw_functionTable {
	enum {
		_luaw_testFunction,
		_luaw_amelog,
		_luaw_printError,
		_luaw_sendMsgToAllClients,
		_luaw_mapAddObject,
		_luaw_lastFunction
	} id;
	char name[16];
	lua_CFunction function;
};

LUAW_FUNCTION(testFunction);
LUAW_FUNCTION(amelog);
LUAW_FUNCTION(printError);
LUAW_FUNCTION(sendMsgToAllClients);
LUAW_FUNCTION(mapAddObject);

static struct luaw_functionTable luaw_functions[] = {
	{ _luaw_testFunction, "testFunction", luaw_testFunction },
	{ _luaw_amelog, "amelog", luaw_amelog },
	{ _luaw_printError, "printerror", luaw_printError },
	{ _luaw_sendMsgToAllClients, "sendToAll", luaw_sendMsgToAllClients },
	{ _luaw_mapAddObject, "mapAddObject", luaw_mapAddObject },
	{ _luaw_lastFunction, "", NULL }
};

int luaw_registerFunction(lua_State *L, const char *name, lua_CFunction function) {
    lua_pushcfunction(L, function);
    lua_setglobal(L, name);
    amelog("Function \"%s\" sucessfully registred.\n", name);
    return 0;
}

inline void luaw_registerFunctions (lua_State *L) {
	int i;
	for(i=0;i<_luaw_lastFunction;i++) {
		if (luaw_functions[i].function != NULL) {
			luaw_registerFunction(L, luaw_functions[i].name, luaw_functions[i].function);
		}
	}
	amelog("Calling lua/test.lua to make sure is everything olrayts.\n");
	if (!luaL_loadfile(L, "lua/init.lua")) {
		if (lua_pcall(L, 0, LUA_MULTRET, 0))
			amelog("luaError : %s\n", lua_tostring(L, -1));
		lua_pop(L, 1); // remove error message
	}
	else {
		amelog("luaError : %s\n", lua_tostring(L, -1));
			lua_pop(L, 1); // remove error message
	}
}

int luaw_testFunction (lua_State *L) {
	lua_getglobal(L, "print");  /* function to be called */
	lua_pushstring(L, "Hellow from lua wrapper.");
 if (lua_pcall(L, 1, 0, 0) != 0)
  amelog("error running function `f': %s",
		lua_tostring(L, -1));

	amelog("C function sucessfully called from lua and viceversa %%)\n");

	return 0;
}


int luaw_amelog(lua_State *L) {
	if (lua_gettop(L) > 1) {
		luaw_internalPrintError(L, "wrong count arguments for amelog");
		return 0;
	}
	amelog("%s\n", lua_tostring(L, 1));
	return 0;
}

int luaw_printError (lua_State *L) {
  lua_Debug ar;
  lua_getstack(L, 1, &ar);
  lua_getinfo(L, "nSl", &ar);

		char name[128]; char msg[128];
  if (ar.name == NULL)
			strcpy(name, "global context");
  else
  	strcpy(name, ar.name);

  if (lua_gettop(L) == 1)
			strcpy(msg, lua_tostring(L, 1));
  else
  	strcpy(msg, "");


		amelog("error %s in %s, %s:%d\n", msg, name, ar.source, ar.currentline);
  return 0;
}

int luaw_internalPrintError(lua_State *L, const char *msg) {
  lua_Debug ar;
  lua_getstack(L, 1, &ar);
  lua_getinfo(L, "nSl", &ar);
		char tmp[128];
  if (ar.name == NULL)
			strcpy(tmp, "global context");
  else
  	strcpy(tmp, ar.name);
  amelog("Error: %s in %s on %s:%d\n", msg, ar.what, ar.source, ar.currentline);
  return 0;
}

int luaw_sendMsgToAllClients(lua_State *L) {
	int i;
	for (i=0;i<s.highest_fd;i++) {
		if (s.fds[i].type == FD_CLIENT && CLIENT(i)->logged) {
			WFIFOW(CLIENT(i), 0) = 0;
			WFIFOSP(CLIENT(i), (WFIFOB(CLIENT(i), 2) = sprintf(WFIFOP(CLIENT(i), 3), "Hello from lua")));
		}
	}
	return 0;
}

int luaw_mapAddObject (lua_State *L) {
	/*
	This function will be called from luic scripts to actually add into a map an object
	which can be WO_CHAR, WO_ITEM, WO_MOB or whateva.
	To do this we just push a node into cell->objects and we're done... easy nuf
	function mapAddObject(map_hook, x, y, type)
	returns the object
	*/
	amelog("Adding an object to map.\n");
	struct world_map *map = (struct world_map *)lua_touserdata(L, 1);
	int x = lua_tonumber(L, 2);
	int y = lua_tonumber(L, 3);
	int type = lua_tonumber(L, 4);
	int id = lua_tonumber(L, 5);
	char name[16];
	strcpy(name, lua_tostring(L, 6));
	struct world_cell *cell = map_getCell(map, x, y, 0);
	if (!cell)
	{
		amelog("Incorrect cell %d %d for mob %s[%d]\n.", x, y, name, id);
		return 0;
	}
	
	if (type == WO_MOB)
	{
		struct world_mob *mob;
		mob = mob_init(name, cell, id, 0);
		amelog("Monster %s with id %d inited.\n", mob->name, mob->id);
	}
	else if (type == WO_NPC)
	{
		struct world_npc *npc;
		int looklike = lua_tonumber(L, 7); 
		npc = map_addNPC(name, cell, id, looklike); 
	}
	return 0;
}
